{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.1 学习就是参数估计"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import torch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.1.1 一个热门的问题"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "t_c = [0.5,  14.0, 15.0, 28.0, 11.0,  8.0,  3.0, -4.0,  6.0, 13.0, 21.0]\n",
    "t_u = [35.7, 55.9, 58.2, 81.9, 56.3, 48.9, 33.9, 21.8, 48.4, 60.4, 68.4]\n",
    "t_c = torch.tensor(t_c)\n",
    "t_u = torch.tensor(t_u)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.1.4 从问题到PyTorch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def model(t_u, w, b):\n",
    "    return w * t_u + b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def loss_fn(t_p, t_c):\n",
    "    squared_diffs = (t_p - t_c)**2\n",
    "    return squared_diffs.mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([35.7000, 55.9000, 58.2000, 81.9000, 56.3000, 48.9000, 33.9000, 21.8000,\n",
       "        48.4000, 60.4000, 68.4000])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "w = torch.ones(1)\n",
    "b = torch.zeros(1)\n",
    "t_p = model(t_u, w, b)\n",
    "t_p"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(1763.8846)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "loss = loss_fn(t_p, t_c)\n",
    "loss"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.1.5 沿梯度向下"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "delta = 0.1\n",
    "loss_rate_of_change_w = \\\n",
    "    (loss_fn(model(t_u, w + delta, b), t_c) -\n",
    "     loss_fn(model(t_u, w - delta, b), t_c)) / (2.0 * delta)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "learning_rate = 1e-2\n",
    "w = w - learning_rate * loss_rate_of_change_w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "loss_rate_of_change_b = \\\n",
    "    (loss_fn(model(t_u, w, b + delta), t_c) -\n",
    "     loss_fn(model(t_u, w, b - delta), t_c)) / (2.0 * delta)\n",
    "b = b - learning_rate * loss_rate_of_change_b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.1.6 进行分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def loss_fn(t_p, t_c):\n",
    "    squared_diffs = (t_p - t_c)**2\n",
    "    return squared_diffs.mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def dloss_fn(t_p, t_c):\n",
    "    dsq_diffs = 2 * (t_p - t_c)\n",
    "    return dsq_diffs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def model(t_u, w, b):\n",
    "    return w * t_u + b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def dmodel_dw(t_u, w, b):\n",
    "    return t_u\n",
    "\n",
    "def dmodel_db(t_u, w, b):\n",
    "    return 1.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def grad_fn(t_u, t_c, t_p, w, b):\n",
    "    dloss_dw = dloss_fn(t_p, t_c) * dmodel_dw(t_u, w, b)\n",
    "    dloss_db = dloss_fn(t_p, t_c) * dmodel_db(t_u, w, b)\n",
    "    return torch.stack([dloss_dw.mean(), dloss_db.mean()])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.1.7 训练循环"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def training_loop(n_epochs, learning_rate, params, t_u, t_c, print_params = True, verbose=1):\n",
    "    for epoch in range(1, n_epochs + 1):\n",
    "        w, b = params\n",
    "        \n",
    "        t_p = model(t_u, w, b) # 前向传播\n",
    "        loss = loss_fn(t_p, t_c)\n",
    "        grad = grad_fn(t_u, t_c, t_p, w, b) # 反向传播\n",
    "        \n",
    "        params = params - learning_rate * grad\n",
    "        \n",
    "        if epoch % verbose == 0:\n",
    "            print('Epoch %d, Loss %f' % (epoch, float(loss)))\n",
    "            if print_params:\n",
    "                print('    Params: ', params)\n",
    "                print('    Grad  : ', grad)\n",
    "    return params"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1, Loss 1763.884644\n",
      "    Params:  tensor([-44.1730,  -0.8260])\n",
      "    Grad  :  tensor([4517.2964,   82.6000])\n",
      "Epoch 2, Loss 5802484.500000\n",
      "    Params:  tensor([2568.4011,   45.1637])\n",
      "    Grad  :  tensor([-261257.4062,   -4598.9707])\n",
      "Epoch 3, Loss 19408031744.000000\n",
      "    Params:  tensor([-148527.7344,   -2616.3933])\n",
      "    Grad  :  tensor([15109615.0000,   266155.7188])\n",
      "Epoch 4, Loss 64915909902336.000000\n",
      "    Params:  tensor([8589997.0000,  151310.8750])\n",
      "    Grad  :  tensor([-8.7385e+08, -1.5393e+07])\n",
      "Epoch 5, Loss 217130439561707520.000000\n",
      "    Params:  tensor([-4.9680e+08, -8.7510e+06])\n",
      "    Grad  :  tensor([5.0539e+10, 8.9023e+08])\n",
      "Epoch 6, Loss 726257020202974707712.000000\n",
      "    Params:  tensor([2.8732e+10, 5.0610e+08])\n",
      "    Grad  :  tensor([-2.9229e+12, -5.1486e+10])\n",
      "Epoch 7, Loss 2429181687085405986357248.000000\n",
      "    Params:  tensor([-1.6617e+12, -2.9270e+10])\n",
      "    Grad  :  tensor([1.6904e+14, 2.9776e+12])\n",
      "Epoch 8, Loss 8125117236949438203699396608.000000\n",
      "    Params:  tensor([9.6102e+13, 1.6928e+12])\n",
      "    Grad  :  tensor([-9.7764e+15, -1.7221e+14])\n",
      "Epoch 9, Loss 27176865195881116022129584766976.000000\n",
      "    Params:  tensor([-5.5580e+15, -9.7903e+13])\n",
      "    Grad  :  tensor([5.6541e+17, 9.9596e+15])\n",
      "Epoch 10, Loss 90901075478458130961171361977860096.000000\n",
      "    Params:  tensor([3.2144e+17, 5.6621e+15])\n",
      "    Grad  :  tensor([-3.2700e+19, -5.7600e+17])\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "tensor([3.2144e+17, 5.6621e+15])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "training_loop(\n",
    "            n_epochs = 10,\n",
    "            learning_rate = 1e-2,\n",
    "            params = torch.tensor([1.0, 0.0]),\n",
    "            t_u = t_u,\n",
    "            t_c = t_c)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1, Loss 1763.884644\n",
      "    Params:  tensor([ 0.5483, -0.0083])\n",
      "    Grad  :  tensor([4517.2964,   82.6000])\n",
      "Epoch 2, Loss 323.090546\n",
      "    Params:  tensor([ 0.3623, -0.0118])\n",
      "    Grad  :  tensor([1859.5493,   35.7843])\n",
      "Epoch 3, Loss 78.929634\n",
      "    Params:  tensor([ 0.2858, -0.0135])\n",
      "    Grad  :  tensor([765.4666,  16.5122])\n",
      "Epoch 4, Loss 37.552845\n",
      "    Params:  tensor([ 0.2543, -0.0143])\n",
      "    Grad  :  tensor([315.0790,   8.5787])\n",
      "Epoch 5, Loss 30.540285\n",
      "    Params:  tensor([ 0.2413, -0.0149])\n",
      "    Grad  :  tensor([129.6733,   5.3127])\n",
      "Epoch 6, Loss 29.351152\n",
      "    Params:  tensor([ 0.2360, -0.0153])\n",
      "    Grad  :  tensor([53.3496,  3.9682])\n",
      "Epoch 7, Loss 29.148882\n",
      "    Params:  tensor([ 0.2338, -0.0156])\n",
      "    Grad  :  tensor([21.9304,  3.4148])\n",
      "Epoch 8, Loss 29.113848\n",
      "    Params:  tensor([ 0.2329, -0.0159])\n",
      "    Grad  :  tensor([8.9964, 3.1869])\n",
      "Epoch 9, Loss 29.107145\n",
      "    Params:  tensor([ 0.2325, -0.0162])\n",
      "    Grad  :  tensor([3.6721, 3.0930])\n",
      "Epoch 10, Loss 29.105242\n",
      "    Params:  tensor([ 0.2324, -0.0166])\n",
      "    Grad  :  tensor([1.4803, 3.0544])\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "tensor([ 0.2324, -0.0166])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "training_loop(\n",
    "            n_epochs = 10,\n",
    "            learning_rate = 1e-4,\n",
    "            params = torch.tensor([1.0, 0.0]),\n",
    "            t_u = t_u,\n",
    "            t_c = t_c)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "t_un = 0.1 * t_u"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1, Loss 80.364342\n",
      "    Params:  tensor([1.7761, 0.1064])\n",
      "    Grad  :  tensor([-77.6140, -10.6400])\n",
      "Epoch 2, Loss 37.574917\n",
      "    Params:  tensor([2.0848, 0.1303])\n",
      "    Grad  :  tensor([-30.8623,  -2.3864])\n",
      "Epoch 3, Loss 30.871077\n",
      "    Params:  tensor([2.2094, 0.1217])\n",
      "    Grad  :  tensor([-12.4631,   0.8587])\n",
      "Epoch 4, Loss 29.756193\n",
      "    Params:  tensor([2.2616, 0.1004])\n",
      "    Grad  :  tensor([-5.2218,  2.1327])\n",
      "Epoch 5, Loss 29.507149\n",
      "    Params:  tensor([2.2853, 0.0740])\n",
      "    Grad  :  tensor([-2.3715,  2.6310])\n",
      "Epoch 6, Loss 29.392458\n",
      "    Params:  tensor([2.2978, 0.0458])\n",
      "    Grad  :  tensor([-1.2492,  2.8241])\n",
      "Epoch 7, Loss 29.298828\n",
      "    Params:  tensor([2.3059, 0.0168])\n",
      "    Grad  :  tensor([-0.8071,  2.8970])\n",
      "Epoch 8, Loss 29.208717\n",
      "    Params:  tensor([ 2.3122, -0.0124])\n",
      "    Grad  :  tensor([-0.6325,  2.9227])\n",
      "Epoch 9, Loss 29.119417\n",
      "    Params:  tensor([ 2.3178, -0.0417])\n",
      "    Grad  :  tensor([-0.5633,  2.9298])\n",
      "Epoch 10, Loss 29.030487\n",
      "    Params:  tensor([ 2.3232, -0.0710])\n",
      "    Grad  :  tensor([-0.5355,  2.9295])\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "tensor([ 2.3232, -0.0710])"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "training_loop(\n",
    "    n_epochs = 10,\n",
    "    learning_rate = 1e-2,\n",
    "    params = torch.tensor([1.0, 0.0]),\n",
    "    t_u = t_un, # 规范化后的输入\n",
    "    t_c = t_c)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 500, Loss 7.860116\n",
      "Epoch 1000, Loss 3.828538\n",
      "Epoch 1500, Loss 3.092191\n",
      "Epoch 2000, Loss 2.957697\n",
      "Epoch 2500, Loss 2.933134\n",
      "Epoch 3000, Loss 2.928648\n",
      "Epoch 3500, Loss 2.927831\n",
      "Epoch 4000, Loss 2.927680\n",
      "Epoch 4500, Loss 2.927651\n",
      "Epoch 5000, Loss 2.927648\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "tensor([  5.3671, -17.3012])"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "params = training_loop(\n",
    "    n_epochs = 5000,\n",
    "    learning_rate = 1e-2,\n",
    "    params = torch.tensor([1.0, 0.0]),\n",
    "    t_u = t_un,\n",
    "    t_c = t_c,\n",
    "    print_params = False,\n",
    "    verbose=500)\n",
    "params"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "t_p = model(t_un, *params) # 记住你是在规范后数据上训练的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x112f642e8>]"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\nAkFERAD4f8Rye5niu2DWAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x112f68978>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure()\n",
    "plt.xlabel(\"Fahrenheit\")\n",
    "plt.ylabel(\"Celsius\")\n",
    "\n",
    "plt.plot(t_u.numpy(), t_p.detach().numpy()) # 在原数据上作图\n",
    "plt.plot(t_u.numpy(), t_c.numpy(), 'o')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
